﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Reflection;
using Microsoft.TeamFoundation.Client;
using Mono.Options;
using TfsWrapper.Commands;

namespace TfsWrapper
{
    public class TfsWrapper : IDisposable
    {
        private TfsTeamProjectCollection tfs;

        public void Execute(TextWriter @out, IEnumerable<string> args)
        {
            var server = string.Empty;
            var user = string.Empty;
            var password = string.Empty;

            string commandName = null;
            var verbose = false;

            var options = new OptionSet(); 
            
            options = new OptionSet
            {
                {"s|server=", "{Url} of the Tfs server", s => server = s},
                {"u|user=", "{Username} to use when connecting to Tfs. If not provided the credentials of the running process will be used", u => user = u},
                {"p|password=", p => password = p},
                {"c|command=", "{Command} to execute: " + AvailableCommands, c => commandName = c},
                {"v|verbose", "Whether to print descriptive labels together with the output results", ignored => verbose = true},
                {"h|help|?", "Prints this help and exits", ignored => ShowHelp(@out, options)},
            };

            var commandArgs = options.Parse(args);

            var outputWriter = verbose
                                   ? new VerboseOutputWriter(@out)
                                   : new OutputWriter(@out);

            var command = TfsCommand.FromName(commandName, outputWriter);

            var localTfs = GetTfs(server, user, password);

            localTfs.EnsureAuthenticated();
            command.Execute(localTfs, commandArgs.ToArray());
        }

        private static string AvailableCommands
        {
            get { return string.Join(", ", TfsCommand.CommandNames); }
        }

        private static void ShowHelp(TextWriter @out, OptionSet options)
        {
            @out.Write("Usage: ");
            @out.WriteLine("{0} [options] [command arguments]", Path.GetFileName(Assembly.GetExecutingAssembly().Location));
            @out.WriteLine();
            @out.WriteLine("Options:");
            @out.WriteLine();

            options.WriteOptionDescriptions(@out);
            Environment.Exit(0);
        }

        private TfsTeamProjectCollection GetTfs(string server, string user, string password)
        {
            return tfs = string.IsNullOrEmpty(user) == false
                ? GetAuthenticatedTfs(server, user, password)
                : GetUnauthenticatedTfs(server);
        }

        private TfsTeamProjectCollection GetUnauthenticatedTfs(string server)
        {
            return new TfsTeamProjectCollection(new Uri(server));
        }

        private TfsTeamProjectCollection GetAuthenticatedTfs(string server, string user, string password)
        {
            var fullUsername = user.Split('\\');

            var networkCredential = fullUsername.Length == 2
                ? new NetworkCredential(fullUsername[1], password, fullUsername[0])
                : new NetworkCredential(fullUsername[0], password);

            return new TfsTeamProjectCollection(new Uri(server), 
                new TfsClientCredentials(new BasicAuthCredential(networkCredential)) { AllowInteractive = false });
        }

        public void Dispose()
        {
            if(tfs != null)
                tfs.Dispose();
        }
    }
}